summaryrefslogtreecommitdiff
path: root/src/image.cpp
blob: 122df6529c47bbe0c2f4051a5e1cff850cb02d73 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include "image.h"
#include "palette.h"
#include "font.h"

#include <stdlib.h>
#include <string.h>
#include <png.h>
#include <math.h>

Image::Image() :
    iWidth( 0 ),
    iHeight( 0 ),
    pPix( NULL )
{
}

Image::Image( int32_t iWidth, int32_t iHeight ) :
    iWidth( iWidth ),
    iHeight( iHeight ),
    pPix( NULL )
{
    pPix = new uint8_t[iWidth*iHeight];
    clear();
}

Image::~Image()
{
    delete[] pPix;
}

int Image::getWidth() const
{
    return iWidth;
}

int Image::getHeight() const
{
    return iHeight;
}

void Image::clear( uint8_t uColor )
{
    memset( pPix, uColor, iWidth*iHeight );
}

void Image::set( int32_t x, int32_t y, uint8_t iCol )
{
    if( x < 0 || y < 0 || x >= iWidth || y >= iHeight )
        return;

    pPix[x+y*iWidth] = iCol;
}

void Image::save( const char *sPath, class Palette &rPal )
{
    uint8_t **pRows = new uint8_t*[iHeight];
    for( int r = 0; r < iHeight; r++ )
    {
        pRows[r] = pPix+(iWidth*r);
    }

    png_structp png_ptr = png_create_write_struct(
        PNG_LIBPNG_VER_STRING, NULL, NULL, NULL
        );
    png_infop info_ptr = png_create_info_struct(png_ptr);
    png_set_IHDR(png_ptr, info_ptr, iWidth, iHeight,
        8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
        PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT
        );
    png_color *pCol = new png_color[rPal.getCount()];
    for( int j = 0; j < rPal.getCount(); j++ )
    {
        uint8_t r, g, b;
        rPal.getColor( j, r, g, b );
        pCol[j].red = r;
        pCol[j].green = g;
        pCol[j].blue = b;
    }
    png_set_PLTE( png_ptr, info_ptr, pCol, rPal.getCount());

    png_set_rows( png_ptr, info_ptr, pRows );

    FILE *fp = fopen(sPath, "wb");
    if( fp == NULL )
    {
        printf("Error opening file!\n");
        exit( 1 );
    }
    
    png_init_io( png_ptr, fp );
    png_write_png( png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL );
    png_destroy_write_struct( &png_ptr, &info_ptr );
    fclose( fp );

    delete[] pCol;
    delete[] pRows;
}

void Image::drawText( class Font &rFnt, int32_t x, int32_t y, uint8_t uColor,
        const char *sText )
{
    for( const char *s = sText; *s; s++ )
    {
        Font::Glyph *pGlyph = rFnt.get( *s );
        if( pGlyph == NULL )
            continue;

        for( int cy = 0; cy < pGlyph->pBox.y; cy++ )
        {
            for( int cx = 0; cx < pGlyph->pBox.x; cx++ )
            {
                int bit = 1<<(7-(cx%8));
                int byte = cx/8;
                if( pGlyph->pData[byte+cy*pGlyph->iRowBytes]&bit )
                    set( x+cx, y+cy-pGlyph->pBox.y-pGlyph->pOff.y, uColor );
            }
        }
        x += pGlyph->pDevOff.x;
        y += pGlyph->pDevOff.y;
    }
}

void Image::drawLine( int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint8_t uColor )
{
    if( x1 == x2 )
    {
        // Vertical line, easy
        if( y2 < y1 )
        {
            int32_t r = y2;
            y2 = y1;
            y1 = r;
        }
        for( int j = y1; j <= y2; j++ )
        {
            set( x1, j, uColor );
        }
    }
    else if( y1 == y2 )
    {
        // Horizontal line, easy
        if( x2 < x1 )
        {
            int32_t r = x2;
            x2 = x1;
            x1 = r;
        }
        for( int j = x1; j <= x2; j++ )
        {
            set( j, y1, uColor );
        }
    }
    else
    {
        int xd = x2-x1;
        int yd = y2-y1;
        float d = sqrt( xd*xd + yd*yd );
        float ux = xd/d;
        float uy = yd/d;

        float x = x1;
        float y = y1;

        set( (int)x, (int)y, uColor );
        for( float n = 0.0; n < d; n += 1.0 )
        {
            x += ux;
            y += uy;
            set( (int)x, (int)y, uColor );
        }
    }
}